﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Windows.Input;
using Kokomo.PeInspector.Reflection.Disassembly;
using Kokomo.Environment;
using System.Threading;
using System.Windows.Media;
using Kokomo.Environment.Commanding;
using System.Windows;
using Kokomo.Environment.Documents;
using Kokomo.Environment.Services;

namespace Kokomo.PeInspector.Reflection
{
	[ViewType(typeof(AssemblyStringsView))]
	class AssemblyStringsViewModel : SearchViewModel<TreeNodeViewModel>
	{

		public AssemblyStringsViewModel(
			Assembly assembly,
			IDictionary<string, StringDependencyGroup> stringGroups,
			IMetadataHost host,
			ICommand navigateToCommand
			)
		{
			if (assembly == null) throw new ArgumentNullException("assembly");
			if (host == null) throw new ArgumentNullException("host");

			this.Assembly = assembly;
			this.Host = host;
			this.NavigateToCommand = navigateToCommand;

			this._stringGroups = stringGroups;
			this.BuildNodes();
		}

		public Assembly Assembly { get; private set; }
		public IMetadataHost Host { get; private set; }
		public ICommand NavigateToCommand { get; private set; }

		private IDictionary<string, StringDependencyGroup> _stringGroups;
		private IEnumerable<TreeNodeViewModel> _stringGroupNodes;

		private void BuildNodes()
		{
			ImageSource copyIcon = EnvironmentServices.GetService<IImageProvider>().GetImage(StandardImageKeys.Copy);
			ImageSource stringIcon = AssemblyAnalyzerEditor.MetadataIconProvider.GetImage(ImageKeys.String);
			List<TreeNodeViewModel> nodes = new List<TreeNodeViewModel>();
			ICommand copyTextCommand = new ParameterizedCommand(this.CopyText);
			foreach (var group in this._stringGroups.Values)
			{
				List<TreeNodeViewModel> dependentNodes = new List<TreeNodeViewModel>();

				foreach (var dependent in group.Constants)
				{
					MemberViewInfo memberViewInfo = MemberViewInfo.GetMemberViewInfo(dependent);
					TreeNodeViewModel dependentNode = new TreeNodeViewModel(
						AssemblyAnalyzerEditor.MetadataIconProvider.GetImage(memberViewInfo.IconKey),
						memberViewInfo.LongHeading,
						dependent
						);
					dependentNodes.Add(dependentNode);
				}
				foreach (var dependent in group.Methods)
				{
					MemberViewInfo memberViewInfo = MemberViewInfo.GetMemberViewInfo(dependent);
					TreeNodeViewModel dependentNode = new TreeNodeViewModel(
						AssemblyAnalyzerEditor.MetadataIconProvider.GetImage(memberViewInfo.IconKey),
						memberViewInfo.LongHeading,
						dependent
						);
					dependentNodes.Add(dependentNode);
				}

				TreeNodeViewModel groupNode = new TreeNodeViewModel(
					stringIcon,
					UiString.FromString(string.Format("\"{0}\"", group.String)),
					group
					)
				{
					ItemsSource = dependentNodes,
					ContextMenuItems = new MenuItemViewModel[]{
						new MenuCommandItemViewModel(new CommandViewModel(
							copyTextCommand,
							UiString.FromString(Messages.CopyTextTitle),
							copyIcon
							) { Argument=group.String}
							)
					}
				};

				nodes.Add(groupNode);
			}

			this._stringGroupNodes = nodes;
		}
		private void CopyText(object arg)
		{
			string str = arg as string;
			if (str != null)
				Clipboard.SetText(str);
		}

		protected override IEnumerable<TreeNodeViewModel> OnSearchAsync(
			string searchTerm,
			int searchVersion
			)
		{
			if (string.IsNullOrEmpty(searchTerm))
			{
				return this._stringGroupNodes;
			}
			else
			{
				var groupNodes = this._stringGroupNodes;
				if (groupNodes != null)
				{
					List<TreeNodeViewModel> resultNodes = new List<TreeNodeViewModel>();
					foreach (var node in groupNodes)
					{
						if (this.SearchVersion != searchVersion) return null;

						StringDependencyGroup group = (StringDependencyGroup)node.Target;
						if (group.String.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase))
							resultNodes.Add(node);
					}

					return resultNodes;
				}
			}

			return null;
		}
	}
}
